package com.fuyao.cloud.personnel.problem.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyao.cloud.admin.api.feign.RemoteNumberService;
import com.fuyao.cloud.admin.api.utils.NumberUtils;
import com.fuyao.cloud.common.core.util.R;
import com.fuyao.cloud.common.data.datascope.DataScope;
import com.fuyao.cloud.common.excel.vo.ErrorMessage;
import com.fuyao.cloud.personnel.api.constant.ProblemInfoConstant;
import com.fuyao.cloud.personnel.api.constant.RectifyConstant;
import com.fuyao.cloud.personnel.api.entity.ProblemCti;
import com.fuyao.cloud.personnel.api.entity.ProblemInfor;
import com.fuyao.cloud.personnel.api.entity.ProblemRectify;
import com.fuyao.cloud.personnel.api.vo.excel.ProblemInforExcelVO;
import com.fuyao.cloud.personnel.api.vo.excel.ProblemInforExportExcelVO;
import com.fuyao.cloud.personnel.problem.mapper.ProblemCtiMapper;
import com.fuyao.cloud.personnel.problem.mapper.ProblemInforMapper;
import com.fuyao.cloud.personnel.problem.mapper.ProblemRectifyMapper;
import com.fuyao.cloud.personnel.problem.service.ProblemInforService;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindingResult;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 问题管理
 *
 * @author pigx code generator
 * @date 2022-04-26 10:13:59
 */
@Service
@AllArgsConstructor
public class ProblemInforServiceImpl extends ServiceImpl<ProblemInforMapper, ProblemInfor> implements ProblemInforService {

    private final RemoteNumberService remoteNumberService;

    private final ProblemCtiMapper ctiMapper;
    private final ProblemRectifyMapper rectifyMapper;

    @Override
    public <E extends IPage<ProblemInfor>> E page(E page, Wrapper<ProblemInfor> queryWrapper) {
        return this.baseMapper.selectPageByScope(page,queryWrapper,new DataScope());
    }

    @Override
    public boolean save(ProblemInfor entity) {
        entity.setNumber(getOnlyNum());
        entity.setStatus(ProblemInfoConstant.DRAFT_VAL);
        setProblemCti(entity);

        AssertUtil.isTrue(!checkImportProblemInforExists(entity.getInfor(),entity.getYear(),entity.getCtiName()),"该问题已存在，请修改分类、问题描述、年度后添加");
        return super.save(entity);
    }

    @Override
    public boolean updateById(ProblemInfor entity) {
        setProblemCti(entity);
        List<ProblemRectify> problemRectifyList = this.rectifyMapper.selectList(Wrappers.<ProblemRectify>query().lambda().eq(ProblemRectify::getProblemInforId, entity.getId()));
        if(entity.getStatus() == 2 && CollUtil.isNotEmpty(problemRectifyList)){
            problemRectifyList.forEach(problemRectify -> {
                problemRectify.setCompletion(RectifyConstant.HAS_RECTIFICATION_VAL);
                this.rectifyMapper.updateById(problemRectify);
            });
        }
        return super.updateById(entity);
    }

    @Override
    public String getOnlyNum() {
        // 默认
        String onlyNum = "00001";
        ProblemInfor infor = this.baseMapper.selectOne(Wrappers.<ProblemInfor>lambdaQuery().orderByDesc(ProblemInfor::getId).last("LIMIT 1"));
        if (infor!=null){
            onlyNum = NumberUtils.getIncrementNum(infor.getNumber().substring(10));
        }
        return ProblemInfoConstant.PROBLEM_INFO_TYPE+ DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)+onlyNum;
    }

    @Override
    public R updateStatus(Long id,Integer status) {
        ProblemInfor problemInfor = new ProblemInfor();
        if (status.intValue() == ProblemInfoConstant.DRAFT_VAL ||
            status.intValue() == ProblemInfoConstant.PROCESSING_VAL ||
            status.intValue() == ProblemInfoConstant.HAS_BEEN_COMPLETED_VAL||
            status.intValue() == ProblemInfoConstant.INVALID_VAL){
            problemInfor.setId(id);
            problemInfor.setStatus(status);
            return R.ok(baseMapper.updateById(problemInfor));
        }
        return R.failed("状态不存在");
    }

    @Override
    public R importProblemInfor(List<ProblemInforExcelVO> excelVOList, BindingResult bindingResult) {
        // 通用校验获取失败的数据
        List<ErrorMessage> errorMessageList = (List<ErrorMessage>) bindingResult.getTarget();

        for (int i = 0; i < excelVOList.size(); i++) {
            ProblemInforExcelVO inforExcelVO = excelVOList.get(i);
            Set<String> errorMsg = new HashSet<>();

            List<ProblemCti> problemCtiList = this.ctiMapper.selectList(Wrappers.<ProblemCti>lambdaQuery().eq(ProblemCti::getName,inforExcelVO.getCtiName()));
            if (problemCtiList.size() == 0){
                errorMsg.add(String.format("分类名称不存在"));
            }

            if(checkImportProblemInforExists(inforExcelVO.getInfor(),inforExcelVO.getYear(),inforExcelVO.getCtiName())){
                errorMsg.add(String.format("%s","问题已存在，请修改分类名称、问题描述、年度"));
            }

            // 数据合法情况
            if (CollUtil.isEmpty(errorMsg)) {
                insertExcelProblemInfo(inforExcelVO,problemCtiList.get(0));
            }
            else {
                // 数据不合法情况
                errorMessageList.add(new ErrorMessage((long) (i + 2), errorMsg));
            }
        }

        if (CollUtil.isNotEmpty(errorMessageList)) {
            return R.failed(errorMessageList);
        }

        return R.ok();
    }

    /**
     * 能过年份和问题描述判断是否存在该问题
     * @param infor 问题描述
     * @param year 年度
     * @return 是否存在 true : false
     */
    private boolean checkImportProblemInforExists(String infor,String year,String ctiName){
        if(StrUtil.isEmpty(infor) || StrUtil.isEmpty(year)){
            return Boolean.FALSE;
        }
        LambdaQueryWrapper<ProblemInfor> queryWrapper = Wrappers.<ProblemInfor>query().lambda()
                .eq(ProblemInfor::getInfor, infor)
                .eq(ProblemInfor::getYear, year)
                .eq(ProblemInfor::getCtiName, ctiName);
        Long count = this.baseMapper.selectCount(queryWrapper);
        return (null!=count && count>0);
    }

    // 保存excel问题信息
    private void insertExcelProblemInfo(ProblemInforExcelVO inforExcelVO,ProblemCti cti) {
        ProblemInfor infor =new ProblemInfor();
        BeanUtils.copyProperties(inforExcelVO,infor);
        infor.setCtiId(cti.getId());
        infor.setCtiFullname(cti.getFullname());
        infor.setCtiFullcode(cti.getFullcode());
        infor.setNumber(getOnlyNum());
        if (inforExcelVO.getStatusStr() == null){
            infor.setStatus(ProblemInfoConstant.DRAFT_VAL);
        } else {
            switch (inforExcelVO.getStatusStr()){
                case ProblemInfoConstant.DRAFT:
                    infor.setStatus(ProblemInfoConstant.DRAFT_VAL);
                    break;
                case ProblemInfoConstant.HAS_BEEN_COMPLETED:
                    infor.setStatus(ProblemInfoConstant.HAS_BEEN_COMPLETED_VAL);
                    break;
                case ProblemInfoConstant.INVALID:
                    infor.setStatus(ProblemInfoConstant.INVALID_VAL);
                    break;
                case ProblemInfoConstant.PROCESSING:
                    infor.setStatus(ProblemInfoConstant.PROCESSING_VAL);
                    break;
            }
        }
        super.save(infor);
    }

    @Override
    public List<ProblemInforExportExcelVO> export(QueryWrapper<ProblemInfor> query) {
        List<ProblemInfor> problemInforList = this.baseMapper.selectListByScope(query, new DataScope());
        List<ProblemInforExportExcelVO> excelVOList = new ArrayList();
        if(CollUtil.isNotEmpty(problemInforList)){
            problemInforList.forEach(infor->{
                ProblemInforExportExcelVO exportExcelVO = new ProblemInforExportExcelVO();
                BeanUtils.copyProperties(infor,exportExcelVO);
                exportExcelVO.setStatus(ProblemInfoConstant.problemInfoMap.get(infor.getStatus()));
                excelVOList.add(exportExcelVO);
            });
        }
        return excelVOList;
    }

    @Override
    public R batchRemoveInforByIds(List<Long> ids) {
        LambdaQueryWrapper<ProblemRectify> queryWrapper = Wrappers.<ProblemRectify>lambdaQuery().in(ProblemRectify::getProblemInforId, ids);
        List<ProblemRectify> rectifyList = rectifyMapper.selectList(queryWrapper);
        StringBuilder resultMessage = StrUtil.builder();
        List<Long> deleteIds = ids;
        List<String> numberList = rectifyList.stream().map(ProblemRectify::getNumber).collect(Collectors.toList());
        if(CollUtil.isNotEmpty(numberList)){
            resultMessage.append("其中整改单号").
                    append(CollUtil.join(numberList,",")).
                    append("以关联问题详情，需要删除整改措施才能删除问题详情。");
            deleteIds = ids.stream().filter(id-> filterDeleteIds(id,rectifyList)).collect(Collectors.toList());
        }
        if(deleteIds.size()>0){
            int deleteBatchCount = this.baseMapper.deleteBatchIds(deleteIds);
            resultMessage.append("成功删除").append(deleteBatchCount).append("问题详情数据");
        }
        if(StrUtil.isEmpty(resultMessage.toString())){
            resultMessage.append("删除失败,请检查数据是否正确");
        }
        return R.ok(resultMessage.toString());
    }
    private boolean filterDeleteIds(Long id,List<ProblemRectify> rectifyList){
        return rectifyList.stream().noneMatch(rectify -> rectify.getProblemInforId().equals(id));
    }
    private void setProblemCti(ProblemInfor entity){
        if (entity.getCtiId() !=null && entity.getCtiId() >0){
            if (entity.getCtiName() == null || entity.getCtiFullcode() == null || entity.getCtiFullname() == null){
                ProblemCti cti = ctiMapper.selectById(entity.getCtiId());
                entity.setCtiName(cti.getName());
                entity.setCtiFullcode(cti.getFullcode());
                entity.setCtiFullname(cti.getFullname());
            }
        }
    }
}
